package de.berlani.geolike;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;

import com.google.android.maps.GeoPoint;

public class GeoUpdater {
	
	private GeoLikeActivity parent;
	private LocationManager locationManager;
	private String provider;
	private Location location = null;
	
	private LocationListener locationListener = new LocationListener(){
		
		public void onLocationChanged(Location newlocation) {
			if(isBetterLocation(newlocation,location)){
				location = newlocation;
				update();
			}
		}

		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub
			
		}

		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub
			
		}

		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub
			
		}
	};
	
	public GeoUpdater(GeoLikeActivity parent){
		this.parent = parent;
		locationManager = (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE);
		Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE);
		provider = locationManager.getBestProvider(criteria, true);
		location = locationManager.getLastKnownLocation(provider);
		locationManager.requestLocationUpdates(provider, 0, 0, locationListener);
		if(location!=null)
			update();
	}
	
	public void pause(){
		stop();
	}
	
	public void stop(){
		locationManager.removeUpdates(locationListener);
	}
	
	public void resume(){
		locationManager.requestLocationUpdates(provider, 400, 1, locationListener);
	}
	
	private void update(){
		Map<String,String> geodata = new HashMap<String,String>();
		
		geodata.put("lon",String.valueOf(location.getLongitude()));
		geodata.put("lat", String.valueOf(location.getLatitude()));
		geodata.put("acc", String.valueOf(location.getAccuracy()));
		
		parent.update(geodata);
	}
	

	/** Determines whether one Location reading is better than the current Location fix
	  * @param location  The new Location that you want to evaluate
	  * @param currentBestLocation  The current Location fix, to which you want to compare the new one
	  */
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	protected static boolean isBetterLocation(Location location, Location currentBestLocation) {
	    if (currentBestLocation == null) {
	        // A new location is always better than no location
	        return true;
	    }

	    // Check whether the new location fix is newer or older
	    long timeDelta = location.getTime() - currentBestLocation.getTime();
	    boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
	    boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
	    boolean isNewer = timeDelta > 0;

	    // If it's been more than two minutes since the current location, use the new location
	    // because the user has likely moved
	    if (isSignificantlyNewer) {
	        return true;
	    // If the new location is more than two minutes older, it must be worse
	    } else if (isSignificantlyOlder) {
	        return false;
	    }

	    // Check whether the new location fix is more or less accurate
	    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
	    boolean isLessAccurate = accuracyDelta > 0;
	    boolean isMoreAccurate = accuracyDelta < 0;
	    boolean isSignificantlyLessAccurate = accuracyDelta > 200;

	    // Check if the old and new location are from the same provider
	    boolean isFromSameProvider = isSameProvider(location.getProvider(),
	            currentBestLocation.getProvider());

	    // Determine location quality using a combination of timeliness and accuracy
	    if (isMoreAccurate) {
	        return true;
	    } else if (isNewer && !isLessAccurate) {
	        return true;
	    } else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
	        return true;
	    }
	    return false;
	}

	/** Checks whether two providers are the same */
	private static boolean isSameProvider(String provider1, String provider2) {
	    if (provider1 == null) {
	      return provider2 == null;
	    }
	    return provider1.equals(provider2);
	}
	
	public GeoPoint getGeoPoint(){
		GeoPoint geopoint = new GeoPoint(
				(int) (location.getLatitude() * 1E6), 
				(int) (location.getLongitude() * 1E6));
		return geopoint;
	}

}
